package com.ysm.smfu.view;

import android.content.Context;
import android.graphics.Rect;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;

/**
 * ====================
 * 版权所有 违法必究
 *
 * @author wangx
 * @project SwipeLayout
 * @file SwipeLayout
 * @create_time 2016/8/29 0029
 * @github https://github.com/wangxujie
 * @blog http://wangxujie.github.io
 * <p/>
 * ======================
 */
public class SwipeLayout extends FrameLayout {

    private ViewDragHelper viewDragHelper;
    private ViewGroup backLayout;
    private ViewGroup frontLayout;
    private int width;
    private int height;
    private int mRange;
    private SwipeState state = SwipeState.CLOSE;//默认关闭状态
    private OnSwipeChangeListener onSwipeChangeListener;
    //3 . 将事件转交给 viewDragHelper对象后,解析,回调
    ViewDragHelper.Callback cb = new ViewDragHelper.Callback() {
        /**根据返回值决定 子view 是否可以拖动*/
        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            // child 直接子view
            // pointerId 多指触摸的 手指id
            return true;
        }

        /**捕获view 的时候调用*/
        @Override
        public void onViewCaptured(View capturedChild, int activePointerId) {
            //capturedChild 被捕获的 子view
            //activePointerId 手指id
            super.onViewCaptured(capturedChild, activePointerId);
        }

        /**决定直接子view 拖动到的位置 还没有真正的移动*/
        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            //child : 直接子view
            //left: 建议达到的位置 = 当前位置+ 瞬间变化的位置
            // dx: 水平方向瞬间变化量

            // 修正 frontLayout拖动范围
            if (child == frontLayout) {
                left = fixFrontLeft(left);
            } else if (child == backLayout) { // 修正backLayout的拖动范围
                left = fixBackLeft(left);
            }
            return left;
        }

        private int fixBackLeft(int left) {
            if (left < width - mRange) {
                left = width - mRange;
            } else if (left > width) {
                left = width;
            }
            return left;
        }

        private int fixFrontLeft(int left) {
            if (left < -mRange) {
                left = -mRange;
            } else if (left > 0) {
                left = 0;
            }
            return left;
        }

        /**获取横向拖动范围  返回值> 0即可  抗干扰*/
        @Override
        public int getViewHorizontalDragRange(View child) {
            return mRange;
        }

        /**发生了真正的移动 1,添加状态更新 2.伴随动画 3.添加回调*/
        @Override
        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
            //changedView: 位置改变的view
            //left :clampViewPositionHorizontal的返回值
            //dx:水平方向的瞬间变化量
            if (changedView == frontLayout) {
                //当前拖动的是 frontLayout ,将瞬间变化量dx 转交给 backLayout
                backLayout.offsetLeftAndRight(dx);
            } else if (changedView == backLayout) {
                //拖动的是 backLayout  ,将瞬间变化量 转交给 frontLayout
                frontLayout.offsetLeftAndRight(dx);
            }
            dispatchEvent();
            // 手动刷新 重新绘制 兼容低版本
            invalidate();
        }

        /**当view 释放的时候调用 */
        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
            //releasedChild: 拖动的view对象 子view s =vt
            //xvel: 水平方向的释放时速度  向左 -   向右 +  0(在手指停止后释放)
            if (xvel < 0) {
                //打开
                open();
            } else if (xvel == 0 && frontLayout.getLeft() < -mRange * 1.0f / 2) {
                //打开
                open();
            } else {
                //     关闭
                close();
            }
        }
    };

    private float downX;
    private float downY;

    public SwipeLayout(Context context) {
        this(context, null);
    }

    public SwipeLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SwipeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        //1. 初始化 ViewDragHelper

        viewDragHelper = ViewDragHelper.create(this, 1.0f, cb);
    }

    public OnSwipeChangeListener getOnSwipeChangeListener() {
        return onSwipeChangeListener;
    }

    public void setOnSwipeChangeListener(OnSwipeChangeListener onSwipeChangeListener) {
        this.onSwipeChangeListener = onSwipeChangeListener;
    }

    private void dispatchEvent() {
        SwipeState preState = state;//记录上一个状态
        state = updateState();//最新状态
        if (onSwipeChangeListener != null) {
            onSwipeChangeListener.onSwipng(this);
            if (state != preState) {
                // 枚举  表示当前状态 不同于上一个状态
                if (state == SwipeState.OPEN) {
                    onSwipeChangeListener.onOpen(this);
                } else if (state == SwipeState.CLOSE) {
                    onSwipeChangeListener.onClose(this);
                }

                //将要打开 上一个状态是 关闭状态
                if (preState == SwipeState.CLOSE) {
                    onSwipeChangeListener.onStartOpen(this);
                } else if (preState == SwipeState.OPEN) {//将要关闭上一个状态是 打开状态
                    onSwipeChangeListener.onStartClose(this);
                }
            }
        }
    }

    /**
     * 获取最新状态
     *
     * @return
     */
    private SwipeState updateState() {
        if (frontLayout.getLeft() == -mRange) {
            //打开
            return SwipeState.OPEN;
        } else if (frontLayout.getLeft() == 0) {
            return SwipeState.CLOSE;
        }
        return SwipeState.SWIPING;//正在拖动
    }

    @Override
    public void computeScroll() {
        super.computeScroll();

        //是否继续触发动画
        boolean b = viewDragHelper.continueSettling(true);
        if (b) {
            //执行动画
            ViewCompat.postInvalidateOnAnimation(this);
        }
    }

    public void open(boolean isSmooth) {
        // Scroller : 计算器
        if (isSmooth) {
            // 是否触发动画
            boolean b = viewDragHelper.smoothSlideViewTo(frontLayout, -mRange, 0);
            if (b) {
                //执行动画
                ViewCompat.postInvalidateOnAnimation(this);
            }
        } else {
            layoutInit(true);
        }
    }

    /**
     * 打开
     */
    public void open() {
        open(true);//默认平滑打开
    }

    public void close(boolean isSmooth) {
        if (isSmooth) {
            boolean b = viewDragHelper.smoothSlideViewTo(frontLayout, 0, 0);
            if (b) {
                //执行动画
                ViewCompat.postInvalidateOnAnimation(this);
            }
        } else {
            layoutInit(false);//关闭
        }
    }

    /**
     * 关闭
     */
    public void close() {
        close(true);//默认平滑关闭
    }

    // 2.将事件转交给 viewDragHelper对象
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                downX = ev.getX();
                downY = ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                float moveX = ev.getX();
                float moveY = ev.getY();
                float disX = moveX - downX;
                float dixY = moveY - downY;
                if (Math.abs(disX) > Math.abs(dixY)) {
                   getParent().requestDisallowInterceptTouchEvent(true);
                }else
                    getParent().requestDisallowInterceptTouchEvent(false);
                downX = moveX;
                downY = moveY;
                break;
        }
        //取决于viewDragHelper对象 是否拦截事件viewDragHelper.shouldInterceptTouchEvent(ev)
        return viewDragHelper.shouldInterceptTouchEvent(ev);
    }

    // 处理触摸事件
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // 将事件转交给 viewDragHelper对象
        viewDragHelper.processTouchEvent(event);
        return true;//事件的消费  目的是为了收到 move + up
    }

    /**
     * 在xml 填充为view对象的时候调用的方法
     */
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        // 健壮性判断
        if (getChildCount() < 2) {
            throw new IllegalStateException("You must be have 2 children at least!");
        }

        if (!(getChildAt(0) instanceof ViewGroup) || !(getChildAt(1) instanceof ViewGroup)) {
            throw new IllegalArgumentException("Your child must be instance of ViewGroup!");
        }

        //获取子view
        backLayout = (ViewGroup) getChildAt(0);
        frontLayout = (ViewGroup) getChildAt(1);
    }

    // 测量获取子view 的宽度
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        //获取  宽高  横向拖动的范围
        width = getMeasuredWidth();
        height = getMeasuredHeight();
        mRange = backLayout.getMeasuredWidth();
    }

    /**
     * 放置子view
     */
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);

        layoutInit(false);
    }

    private void layoutInit(boolean isOpen) {
        Rect mFrontRect = computeFrontRect(isOpen);
        frontLayout.layout(mFrontRect.left, mFrontRect.top, mFrontRect.right, mFrontRect.bottom);
        Rect mBackRect = computeBackRect(mFrontRect);
        backLayout.layout(mBackRect.left, mBackRect.top, mBackRect.right, mBackRect.bottom);

        //系统方法  将 位置改变
        bringChildToFront(frontLayout);
    }

    /**
     * 计算 后边矩形位置
     *
     * @param mFrontRect
     * @return
     */
    private Rect computeBackRect(Rect mFrontRect) {
        int left = mFrontRect.right;
        return new Rect(left, mFrontRect.top, left + mRange, mFrontRect.bottom);
    }

    /**
     * 计算前边矩形位置
     *
     * @return
     */
    private Rect computeFrontRect(boolean isOpen) {
        int left;
        if (!isOpen) {
            left = 0;
        } else {
            left = -mRange;
        }
        return new Rect(left, 0, left + width, 0 + height);
    }

    public enum SwipeState {
        OPEN, CLOSE, SWIPING
    }

    public interface OnSwipeChangeListener {
        void onOpen(SwipeLayout layout);

        void onClose(SwipeLayout layout);

        void onSwipng(SwipeLayout layout);//拖动中

        void onStartOpen(SwipeLayout layout);//将要打开

        void onStartClose(SwipeLayout layout);//将要关闭
    }
}
